home *** CD-ROM | disk | FTP | other *** search
- $TITLE ('KERMIT - MAIN MODULE')
- kermit:
-
- /* COPYRIGHT (C) 1985, Trustees of Columbia University in the City of New */
- /* York. Permission is granted to any individual or institution to use, */
- /* copy, or redistribute this software so long as it is not sold for */
- /* profit, provided this copyright notice is retained. /*
-
- /* Contains the following public routines: */
- /* cmdtail, exhelp, ioinit, newline, nin, nout, print, procbaud, spin, */
- /* strcmp, synerr, token, upcase, and varcmp */
-
- /* NOTE: See the comment below regarding the default "escape" character */
-
- do;
-
- declare true literally '0FFH';
- declare false literally '00H';
-
- /* UART control bits */
- declare port1cmd literally '0F5H';
- declare port1dat literally '0F4H';
- declare port1clk literally '0F0H';
- declare timing1 literally '036H';
- declare port2cmd literally '0F7H';
- declare port2dat literally '0F6H';
- declare port2clk literally '0F1H';
- declare timing2 literally '076H';
- declare modesel literally '0F3H';
- declare reset literally '040H';
- declare EnaTxRx literally '025H';
- declare tx$rdy literally '01H';
- declare rx$rdy literally '02H';
-
- declare null literally '000H';
- declare lf literally '0AH';
- declare cr literally '0DH';
- declare crlf literally 'cr,lf,null';
- declare space literally '20H';
- declare dollar literally '24H';
- declare bel literally '07H';
-
- declare buflen literally '122';
- declare buffer(buflen) byte;
- declare (cmdstr, temp, cmdptr) address;
- declare taking byte public initial(false); /* within "TAKE" file */
- declare continue byte initial(true);
-
- /* ****** Default mode settings ****** */
- /* Note that the default setting for the Kermit "escape" character */
- /* differs from common Kermit usage. This is due to the fact that */
- /* some Intel workstations (e.g. Series III) cannot generate a */
- /* "control-right bracket" character. If you are using only Series */
- /* IV workstations, you can change the initial value below to suit, */
- /* for example, to 29 for control-right bracket. Alternately, you */
- /* can use the "SET ESCAPE" command (manually or in an .INI file) */
- /* to alter the escape character each time you invoke Kermit. */
- declare escchar byte public initial(29); /* control-right bracket */
- declare baudrate address public initial(2400); /* port baud rate */
- declare parity byte public initial(0); /* parity */
- /* (0 = None, 1 = Mark, 2 = Space, 3 = Even, 4 = Odd) */
- declare stopbits byte public initial(2); /* number of stop bits */
- /* (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
- declare port byte public initial(2); /* communications port */
- declare maxtry byte public initial(5); /* number of retries */
- declare debug byte public initial(false);
- declare halfduplex byte public initial(false);
- declare warning$flag byte public initial(false); /* dup-named file switch */
- declare take$echo byte public initial(false); /* echo take commands switch */
- declare def$drive(5) byte public initial(0,0,0,0,0); /* default drive */
- declare prompt(20) byte public initial('ISIS-Kermit>',null); /* Kerm. prompt */
- declare def$prompt(20) byte public initial('ISIS-Kermit>',null); /* Default */
-
- declare filename address public;
-
- declare state byte public;
- declare msgnum byte public;
- declare tries byte public;
- declare oldtry byte public;
-
- /* Masks for comm input and output bytes */
- declare input$and byte public;
- declare output$and byte public;
- declare output$or byte public;
-
- declare cmd byte;
- declare speed byte;
-
- /* Kermit parameter defaults */
- declare pksize literally '94';
- declare mytime literally '5';
- declare mynumpads literally '0';
- declare mypadchr literally '0';
- declare myeol literally 'cr';
- declare myquote literally '023H';
-
- /* Current Kermit parameters */
- declare spsize byte public initial(pksize); /* present packet size */
- declare timeint byte public initial(mytime); /* present time out */
- declare numpads byte public initial(mynumpads); /* how many pads to send */
- declare padchar byte public initial(mypadchr); /* present pad character */
- declare eol byte public initial(myeol); /* present eol character */
- declare quote byte public initial(myquote); /* present quote character */
-
- /* Subroutine declarations */
-
- co: procedure(char)external;
- declare char byte;
- end co;
-
- ci: procedure byte external;
- end ci;
-
- getc: procedure (port) byte external;
- declare port byte;
- end getc;
-
- ready: procedure (port) byte external;
- declare port byte;
- end ready ;
-
- read: procedure(jfn, buf, max, count, status)external;
- declare(jfn, buf, max, count, status)address;
- end read;
-
- error: procedure(errnum)external;
- declare(errnum)address;
- end error;
-
- bye:
- procedure external;
- end bye;
-
- connect:
- procedure external;
- end connect;
-
- cwd:
- procedure external;
- end cwd;
-
- exit: procedure external; end exit;
-
- finish:
- procedure external;
- end finish;
-
- get: procedure external;
- end get;
-
- help: procedure external;
- end help;
-
- logout:
- procedure external;
- end logout;
-
- recv: procedure external;
- end recv;
-
- send: procedure external;
- end send;
-
- set: procedure external;
- end set;
-
- show:
- procedure external;
- end show;
-
- take:
- procedure external;
- end take;
-
- takeline: procedure (addr) external;
- declare addr address;
- end takeline;
-
- takeini: procedure external;
- end takeini;
-
- newline:
- procedure public;
- call co(cr);
- call co(lf);
- end newline;
-
- /* SPIN: Searches a string for a character greater than blank */
- spin: procedure(string)address public;
- declare string address;
- declare char based string byte;
-
- do while (char <> null) and (char < 021H);
- string = string + 1;
- end;
- return string;
- end spin;
-
- strcmp: procedure(s1,s2)byte public;
- declare(s1,s2)address;
- declare c1 based s1 byte;
- declare c2 based s2 byte;
- declare retval byte;
-
- retval = 0;
- s1 = spin(s1);
- s2 = spin(s2);
- if not(c1 = c2) then retval = c1 - c2;
- do while (c1 > 0) and (c2 > 0) and (retval=0);
- retval = c1 - c2;
- s1 = s1+1;
- s2 = s2+1;
- end;
- return retval;
-
- end strcmp;
-
- /* varcmp: Compare two variable length strings */
- /* This routine compares corresponding characters in two strings. */
- /* If it finds a null in the first string, it returns the number */
- /* of characters which matched, excluding the null. If it finds */
- /* a null in the second string or a mismatch, it returns a zero. */
-
- varcmp: procedure(s1,s2)byte public;
- declare(s1,s2)address;
- declare c1 based s1 byte;
- declare c2 based s2 byte;
- declare cnt byte;
-
- cnt = 0;
- /* s1 = spin(s1); */
- /* s2 = spin(s2); */
- do while c1 > 0;
- if c2 = 0 then return 0;
- if c1 <> c2 then return 0;
- s1 = s1+1;
- s2 = s2+1;
- cnt = cnt + 1;
- end;
- return cnt;
-
- end varcmp;
-
- /* TOKEN: returns a pointer to a null-terminated token pointed */
- /* to prior to the call by cmdptr. After the call, cmdptr points */
- /* to the end of the original string, or the first character after */
- /* the null character replacing the first whitespace after the first */
- /* token. */
-
- token: procedure address public;
- declare result address;
- declare char based cmdptr byte;
-
- result = 0;
- cmdptr = spin(cmdptr);
- if char <> null then
- do;
- result = cmdptr;
- do while char > ' ';
- cmdptr = cmdptr + 1;
- end;
- if char <> null then
- do;
- char = null;
- cmdptr = cmdptr + 1;
- end;
- end;
- return result;
- end token;
-
- /* CMDTAIL: returns a pointer to the first nonblank character of the */
- /* remainder of the command line, or zero if there were no more */
- /* nonblank characters in the command line. */
-
- cmdtail: procedure address public;
- declare char based cmdptr byte;
-
- cmdptr = spin(cmdptr);
- if char = null then return 0;
- else return cmdptr;
- end cmdtail;
-
- nout: procedure(n) public;
- declare n address;
- declare (quotient, digit) address;
- declare numbuf(8) byte;
- declare index byte;
-
- if n = 0 then
- do;
- call co('0');
- return;
- end;
- index = 1;
- do while (n > 0);
- digit = n mod 10;
- numbuf(index) = digit + '0';
- index = index + 1;
- n = n / 10;
- end;
- do while ((index := index - 1) > 0);
- call co(numbuf(index));
- end;
- end nout;
-
- nin: procedure(string) address public;
- declare string address;
- declare result address;
- declare c based string byte;
-
- result = 0;
- if (string <> 0) then do;
- string = spin(string);
- do while (c >= '0') and (c <= '9');
- result = result * 10 + (c - '0');
- string = string + 1;
- end;
- end;
- return result;
- end nin;
-
- print: procedure(msg) public;
- declare msg address;
- declare c based msg byte;
-
- do while (c > 0) and (c <> '$');
- if c = '\' then
- call newline;
- else
- call co(c);
- msg = msg + 1;
- end;
- end print;
-
-
- synerr: procedure public;
- call print(.('Syntax error\$'));
- end synerr;
-
- /* IOINIT: This routine takes a port number, 0,1 or 2, and a speed in the */
- /* range 0-8 and initializes the required port to work at the required */
- /* speed. The routine returns no parameters. */
-
- ioinit: procedure public;
- declare baud structure (code0(9) byte, code1(9) byte, mult(9) byte)
- /* Low-order byte of counter values */
- data (0BAH, 80H, 40H, 20H, 10H, 20H, 10H, 08H, 04H,
- /* High-order byte of counter values */
- 02H, 0H, 0H, 0H, 0H, 0H, 0H, 0H, 0H,
- /* 8251A command byte baud rate multiplier control bits */
- 02H, 03H, 03H, 03H, 03H, 02H, 02H, 02H, 02H);
- /* 8251A command byte parity and length control bits */
- /* (0=None, 1=Mark, 2=Space, 3=Even, 4=Odd) */
- declare paritymask(5) byte data (0CH, 0CH, 0CH, 38H, 18H);
-
- /* 8251A command byte stop bits control bits */
- /* (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
- declare stopmask(3) byte data (40H, 80H, 0C0H);
-
- /* Mask bytes for comm. input and output bytes */
- declare inp$mask$and(9) byte
- data (0FFH, 7FH, 0FFH, 7FH, 7FH);
- declare out$mask$and(9) byte
- data (0FFH, 0FFH, 07FH, 0FFH, 0FFH);
- declare out$mask$or(9) byte
- data (0H, 80H, 0H, 0H, 0H);
- declare (c, status) byte;
-
- if debug then call print(.('\initializing serial port\$'));
- do case port;
- do;
- if debug then call print(.('port 0 initialized\$'));
- end;
- do;
- if debug then call print(.('port 1 initialized\$'));
- /* Put the USART into a known state by writing */
- /* three zero command bytes to it */
- output(port1cmd) = 0H;
- output(port1cmd) = 0H;
- output(port1cmd) = 0H;
- /* Reset the USART */
- output(port1cmd) = reset;
- output(modesel) = timing1;
- output(port1clk) = baud.code0(speed);
- output(port1clk) = baud.code1(speed);
- output(port1cmd) = (stopmask(stopbits) or paritymask(parity)
- or baud.mult(speed));
- input$and = inp$mask$and(parity);
- output$and = out$mask$and(parity);
- output$or = out$mask$or(parity);
- if debug then
- do;
- call print(.('Mode command: $'));
- call nout(stopmask(stopbits) or paritymask(parity)
- or baud.mult(speed));
- call newline;
- end;
- output(port1cmd) = EnaTxRx;
- if ready(1) > 0 then c = getc(1); /* discard any char */
- end;
- do;
- if debug then call print(.('port 2 initialized\$'));
- /* Put the USART into a known state by writing */
- /* three zero command bytes to it */
- output(port2cmd) = 0H;
- output(port2cmd) = 0H;
- output(port2cmd) = 0H;
- /* Reset the USART */
- output(port2cmd) = reset;
- output(modesel) = timing2;
- output(port2clk) = baud.code0(speed);
- output(port2clk) = baud.code1(speed);
- output(port2cmd) = (stopmask(stopbits) or paritymask(parity)
- or baud.mult(speed));
- input$and = inp$mask$and(parity);
- output$and = out$mask$and(parity);
- output$or = out$mask$or(parity);
- if debug then
- do;
- call print(.('Mode command: $'));
- call nout(stopmask(stopbits) or paritymask(parity)
- or baud.mult(speed));
- call newline;
- end;
- output(port2cmd) = EnaTxRx;
- if ready(2) > 0 then c = getc(2); /* discard any char */
- end;
- end;
- end ioinit;
-
- usage: procedure;
- call print(.('usage: kermit (110|150|300|600|1200|2400|4800|9600$'));
- call print(.('|19200) (1|2)\$'));
- call exit;
- end usage;
-
- procbaud: procedure (newbaud) byte public;
- declare rate(9) address
- data(110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200);
- declare (result, i, done) byte;
- declare newbaud address;
-
- result = false; /* tentative result of "bad rate" */
- i = 0;
- done = false;
- do while (done = false);
- if i > 8 then done = true; /* off end of table */
- else
- if newbaud < rate(i) then done = true; /* not found */
- else
- if newbaud = rate(i) then
- do;
- done = true;
- result = true;
- end;
- else
- i = i + 1; /* try next */
- end;
- if result = true then
- do;
- baudrate = newbaud;
- speed = i;
- end;
- return result;
- end procbaud;
-
- readln: procedure;
- declare (count, status) address;
-
- call read(1, .buffer, buflen, .count, .status);
- if status > 0 then
- do;
- call print(.('READLN FAILED\$'));
- call error(status);
- call exit;
- end;
- buffer(count-2) = 0;
- cmdptr = .buffer;
- end readln;
-
- /* Convert the contents of a string from lower case to upper case */
- upcase: procedure(addr) public;
- declare addr address;
- declare chr based addr byte;
- declare capdiff byte;
- capdiff = 'a' - 'A';
- do while chr <> 0;
- if (chr >= 'a') and (chr <= 'z') then chr = chr - capdiff;
- addr = addr + 1;
- end;
- end upcase;
-
- /* Display help for the EXIT command */
- exhelp: procedure public;
- call print(.('\EXIT\\$'));
- call print(.(' The EXIT command causes KERMIT to terminate and $'));
- call print(.('return to ISIS.\\$'));
- call print(.('Syntax:\\$'));
- call print(.(' EXIT\\$'));
- end exhelp;
-
- /* Get the next command to be executed */
- getcmd: procedure;
- cmdstr = 0;
- do while (cmdstr = 0);
- if taking then
- do; /* Get the command from the "TAKE" file */
- call takeline(.buffer);
- cmdptr = .buffer;
- if takeecho and taking then
- do; /* (Takeline will have turned "taking" off at EOF) */
- call print(.('TAKE command>$'));
- call print(cmdptr);
- call newline;
- end;
- end;
- else
- do; /* Get the command from the console */
- call print(.prompt); /* Display the prompt */
- call readln;
- end;
- cmdstr = token; /* Get the command "word" */
- call upcase(cmdstr); /* Convert to upper case */
- end;
- end getcmd;
-
- /* Execute a Kermit command */
- docmd: procedure;
- if (varcmp(cmdstr,.('BYE',null)) >= 1) then cmd = 1;
- else
- if (varcmp(cmdstr,.('CONNECT',null)) >= 2) then cmd = 2;
- else
- if (varcmp(cmdstr,.('CWD',null)) >= 2) then cmd = 3;
- else
- if (varcmp(cmdstr,.('EXIT',null)) >= 1) then cmd = 4;
- else
- if (varcmp(cmdstr,.('FINISH',null)) >= 1) then cmd = 5;
- else
- if (varcmp(cmdstr,.('GET',null)) >= 1) then cmd = 6;
- else
- if (varcmp(cmdstr,.('HELP',null)) >= 1) then cmd = 7;
- else
- if (varcmp(cmdstr,.('LOGOUT',null)) >= 1) then cmd = 8;
- else
- if (varcmp(cmdstr,.('RECEIVE',null)) >= 1) then cmd = 9;
- else
- if (varcmp(cmdstr,.('SEND',null)) >= 3) then cmd = 10;
- else
- if (varcmp(cmdstr,.('SET',null)) >= 3) then cmd = 11;
- else
- if (varcmp(cmdstr,.('SHOW',null)) >= 2) then cmd = 12;
- else
- if (varcmp(cmdstr,.('TAKE',null)) >= 1) then cmd = 13;
- else
- do;
- call print(.('Invalid or ambiguous command name\$'));
- cmd = 0;
- end;
-
- if (cmd = 1 or cmd = 2 or cmd = 4 or cmd = 5 or cmd = 8 or cmd = 12) then
- if token > 0 then /* Only some commands can have operands */
- do;
- call print(.('Extraneous operand(s) specified\$'));
- cmd = 0;
- end;
-
- do case cmd;
- /* 0 = Command error previously diagnosed */
- do;
- /* Null action */
- end;
- /* 1 = BYE command */
- do;
- call bye;
- continue = false;
- end;
- /* 2 = CONNECT command */
- call connect;
- /* 3 = CWD command */
- call cwd;
- /* 4 = EXIT command */
- continue = false;
- /* 5 = FINISH command */
- call finish;
- /* 6 = GET command */
- call get;
- /* 7 = HELP command */
- call help;
- /* 8 = LOGOUT command */
- call logout;
- /* 9 = RECEIVE command */
- call recv;
- /* 10 = SEND command */
- call send;
- /* 11 = SET command */
- call set;
- /* 12 = SHOW command */
- call show;
- /* 13 = TAKE command */
- call take;
- end;
- end docmd;
-
- /* *** main program *** */
-
- /* Fetch the command line arguments */
- call readln;
-
- /* Read desired baud rate, if supplied */
- temp = token;
- if temp > 0 then baudrate = nin(temp);
-
- /* Get desired port, if supplied */
- temp = token;
- if temp > 0 then port = nin(temp);
-
- /* Check for garbage on the end of the line */
- if token > 0 then call usage;
-
- if (port < 1) or (port > 2) then call usage;
-
- if (procbaud(baudrate) = false) then call usage; /* bad baudrate */
-
- call ioinit;
-
- /* Initialize a "TAKE" condition from "KERMIT.INI" if it exists */
- call takeini;
-
- if not taking then
- do; /* The "INI" file may change the port and/or baud rate */
- call print(.('Serial port $'));
- call nout(port);
- call print(.(', Baud rate $'));
- call nout(baudrate);
- call newline;
- end;
-
- do while (continue);
- call getcmd; /* Get the next command line */
- call docmd; /* Execute the command */
- end;
- call exit;
-
- end kermit;
-